package io.dcloud.uniplugin.tools;

import android.nfc.tech.NfcV;
import android.util.Log;

import java.io.IOException;
import java.util.Arrays;

public class NfcVUtil {


    public static final NfcVUtil instance = new NfcVUtil();

    private NfcVUtil() {
    }

    public static final String TAG = "NfcV";

    private NfcV mNfcV;
    /**
     * UID数组行式
     */
    private byte[] ID;
    private String UID;
    private String DSFID;
    private String AFI;
    /**
     * block的个数
     */
    private int blockNumber;
    /**
     * 一个block长度
     */
    private int oneBlockSize;
    /**
     * 信息
     */
    private byte[] infoRmation;

    /**
     * 初始化
     *
     * @param mNfcV NfcV对象
     * @throws IOException
     */
    public NfcVUtil(NfcV mNfcV) throws IOException {
        this.mNfcV = mNfcV;
        ID = this.mNfcV.getTag().getId();
        byte[] uid = new byte[ID.length];
        int j = 0;
        for (int i = ID.length - 1; i >= 0; i--) {
            uid[j] = ID[i];
            j++;
        }
        this.UID = printHexString(uid);
        getInfoRmation();//获取标签的信息
    }

    public String getUID() {
        return UID;
    }

    /**
     * 取得标签信息
     */
    private byte[] getInfoRmation() throws IOException {
        byte[] cmd = new byte[10];
        cmd[0] = (byte) 0x22; // flag
        cmd[1] = (byte) 0x2B; // command
        System.arraycopy(ID, 0, cmd, 2, ID.length); // UID
        infoRmation = mNfcV.transceive(cmd);
        blockNumber = infoRmation[12];//可使用的数据块数量，一般为27
        oneBlockSize = infoRmation[13];//每个块byte数组的长度，一般为4
        AFI = printHexString(new byte[]{infoRmation[11]});//AFI值在某些领域会需要使用
        DSFID = printHexString(new byte[]{infoRmation[10]});//DSFID值
        Log.i(TAG, "blockNumber: " + blockNumber);
        Log.i(TAG, "getOneBlockSize: " + oneBlockSize);
        Log.i(TAG, "AFI: " + getAFI());
        Log.i(TAG, "DSFID: " + getDSFID());
        Log.d(TAG, "InfoRmation: " + Arrays.toString(infoRmation));
        return infoRmation;
    }

    public String getDSFID() {
        return DSFID;
    }

    public String getAFI() {
        return AFI;
    }

    public int getBlockNumber() {
        return blockNumber + 1;
    }

    public int getOneBlockSize() {
        return oneBlockSize + 1;
    }

    /**
     * 读取一个位置在position的block
     *
     * @param position 要读取的block位置
     * @return 返回内容字符串
     * @throws IOException
     */
    public String readOneBlock(int position) throws IOException {
        byte[] cmd = new byte[11];
        cmd[0] = (byte) 0x22;
        cmd[1] = (byte) 0x20;// 0x20-READ_SINGLE_BLOCK,0x23-所有块
        System.arraycopy(ID, 0, cmd, 2, ID.length); // UID
        cmd[10] = (byte) position;
        byte[] res = mNfcV.transceive(cmd);
        if (res[0] == 0x00) {
            byte[] block = new byte[res.length - 1];
            System.arraycopy(res, 1, block, 0, res.length - 1);
            return printHexString(block);
        }
        return null;
    }

    /**
     * 读取从begin开始end个block
     * begin + count 不能超过blockNumber
     *
     * @param begin block开始位置
     * @param count 读取block数量
     * @return 返回内容字符串
     * @throws IOException
     */
    public String readBlocks(int begin, int count) throws IOException {
        if ((begin + count) > blockNumber) {
            count = blockNumber - begin;
        }
        StringBuffer data = new StringBuffer();
        for (int i = begin; i < count + begin; i++) {
            data.append(readOneBlock(i));
        }
        return data.toString();
    }

    /**
     * 将byte[]转换成16进制字符串
     *
     * @param data 要转换成字符串的字节数组
     * @return 16进制字符串
     */
    private String printHexString(byte[] data) {
        StringBuffer s = new StringBuffer();

        for (byte datum : data) {
            String hex = Integer.toHexString(datum & 0xFF);
            if (hex.length() == 1) {
                hex = '0' + hex;
            }
            s.append(hex);
        }
        return s.toString();
    }

    /**
     * 将数据写入到block,
     *
     * @param position 要写内容的block位置
     * @param data     要写的内容,必须长度为blockOneSize
     * @return false为写入失败，true为写入成功
     * @throws IOException
     */
    public boolean writeBlock(int position, byte[] data) throws IOException {
        byte[] cmd = new byte[15];
        cmd[0] = (byte) 0x22;
        cmd[1] = (byte) 0x21;
        System.arraycopy(ID, 0, cmd, 2, ID.length); // UID
        //block
        cmd[10] = (byte) position;
        //value
        System.arraycopy(data, 0, cmd, 11, data.length);
        byte[] rsp = mNfcV.transceive(cmd);
        return rsp[0] == 0x00;
    }


    /**
     * 获取Rand
     */
    public byte[] getRand() throws IOException {
        byte[] cmd = new byte[11];
        cmd[0] = (byte) 0x22; // flag
        cmd[1] = (byte) 0xB2; // command
        cmd[2] = (byte) 0x04;
        System.arraycopy(ID, 0, cmd, 3, ID.length); // UID
        byte[] rand = mNfcV.transceive(cmd);
        return rand;
    }

    /**
     * 先设置秘钥
     */
    public boolean setPsw(byte[] rand, byte[] psw) throws IOException {
        byte[] cmd = new byte[8 + ID.length];
        cmd[0] = (byte) 0x22; // flag
        cmd[1] = (byte) 0xB3; // command
        cmd[2] = (byte) 0x04;
        System.arraycopy(ID, 0, cmd, 3, ID.length); // UID
        cmd[3 + ID.length] = 1;//读写保护
        cmd[4 + ID.length] = (byte) (psw[0] ^ rand[1]);
        cmd[5 + ID.length] = (byte) (psw[1] ^ rand[2]);
        cmd[6 + ID.length] = (byte) (psw[2] ^ rand[1]);
        cmd[7 + ID.length] = (byte) (psw[3] ^ rand[2]);
        byte[] rsp = mNfcV.transceive(cmd);
        return rsp[0] == 0;
    }

    /**
     * 启用保护
     */
    public boolean protectPage() throws IOException {
        byte[] cmd = new byte[5 + ID.length];
        cmd[0] = (byte) 0x22; // flag
        cmd[1] = (byte) 0xC6; // command
        cmd[2] = (byte) 0x04;
        System.arraycopy(ID, 0, cmd, 3, ID.length); // UID
        cmd[3 + ID.length] = 0;
        cmd[4 + ID.length] = 1;
        byte[] rsp = mNfcV.transceive(cmd);
        return rsp[0] == 0;
    }

    /**
     * 写入秘钥
     * @param psw
     * @return
     * @throws IOException
     */
    public boolean writePsw(byte[] psw) throws IOException {
        byte[] cmd = new byte[8 + ID.length];
        cmd[0] = (byte) 0x22; // flag
        cmd[1] = (byte) 0xB4; // command
        cmd[2] = (byte) 0x04;
        System.arraycopy(ID, 0, cmd, 3, ID.length); // UID
        cmd[3 + ID.length] = 1;
        cmd[4 + ID.length] = (byte) (psw[0]);
        cmd[5 + ID.length] = (byte) (psw[1]);
        cmd[6 + ID.length] = (byte) (psw[2]);
        cmd[7 + ID.length] = (byte) (psw[3]);
        byte[] rsp = mNfcV.transceive(cmd);
        return rsp[0] == 0;
    }

    //结果大写
    private String ByteArrayToHexString(byte[] inarray) {
        int i, j, in;
        String[] hex = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A",
                "B", "C", "D", "E", "F"};
        String out = "";
        for (j = inarray.length - 1; j >= 0; j--) {
            in = (int) inarray[j] & 0xff;
            i = (in >> 4) & 0x0f;
            out += hex[i];
            i = in & 0x0f;
            out += hex[i];
        }
        return out;
    }


    /**
     * String转Hex格式Byte[]
     *
     * @param hexString
     * @return
     */
    public byte[] hexStringToBytes(String hexString) {
        if (hexString == null || hexString.equals("")) {
            return null;
        }
        hexString = hexString.toUpperCase();
        int length = hexString.length() / 2;
        char[] hexChars = hexString.toCharArray();
        byte[] d = new byte[length];
        for (int i = 0; i < length; i++) {
            int pos = i * 2;
            d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));

        }
        return d;
    }

    private static byte charToByte(char c) {
        return (byte) "0123456789ABCDEF".indexOf(c);
    }


    /**
     * 写入AFI数据
     *
     * @param b
     * @return
     * @throws IOException
     */
    public boolean setAFIState(byte b) throws IOException {
        byte[] cmd = new byte[11];
        cmd[0] = (byte) 0x22; // flag
        cmd[1] = (byte) 0x27; // command
        System.arraycopy(ID, 0, cmd, 2, ID.length); // UID
        cmd[10] = b;
        byte[] res = mNfcV.transceive(cmd);
        if (res[0] == 0x00) {
            byte[] cmdNew = new byte[10];
            cmdNew[0] = (byte) 0x22; // flag
            cmdNew[1] = (byte) 0x2B; // command
            System.arraycopy(ID, 0, cmdNew, 2, ID.length); // UID
            AFI = printHexString(new byte[]{infoRmation[11]});
            DSFID = printHexString(new byte[]{infoRmation[10]});

            return true;

            //千万不要锁定，不可逆
//            byte[] cmd2 = new byte[10];
//            cmd2[0] = (byte) 0x22; // flag
//            cmd2[1] = (byte) 0x28; // command
//            System.arraycopy(ID, 0, cmd2, 2, ID.length); // UID
//            byte[] res2 = mNfcV.transceive(cmd2);
//            if(res2[0] == 0x00){
//               return true;
//            }
        }
        return false;
    }

    /**
     * 写入DSFID数据
     *
     * @param b
     * @return
     * @throws IOException
     */
    public boolean setDSFIDState(byte b) throws IOException {
        byte[] cmd = new byte[11];
        cmd[0] = (byte) 0x22; // flag
        cmd[1] = (byte) 0x29; // command
        System.arraycopy(ID, 0, cmd, 2, ID.length); // UID
        cmd[10] = b;
        byte[] res = mNfcV.transceive(cmd);
        if (res[0] == 0x00) {
            byte[] cmdNew = new byte[10];
            cmdNew[0] = (byte) 0x22; // flag
            cmdNew[1] = (byte) 0x2B; // command
            System.arraycopy(ID, 0, cmdNew, 2, ID.length); // UID
            AFI = printHexString(new byte[]{infoRmation[11]});
            DSFID = printHexString(new byte[]{infoRmation[10]});
            return true;

            //千万不要锁定，不可逆
//            byte[] cmd2 = new byte[10];
//            cmd2[0] = (byte) 0x22; // flag
//            cmd2[1] = (byte) 0x2A; // command
//            System.arraycopy(ID, 0, cmd2, 2, ID.length); // UID
//            byte[] res2 = mNfcV.transceive(cmd2);
//            if(res2[0] == 0x00){
//                return true;
//            }
        }
        return false;
    }

    /**
     * 十进制转十六进制 并补位
     */
    public String decimalToHexString(int decimal) {
        // 转换为十六进制字符串
        String hexString = Integer.toHexString(decimal);
        // 补足位数
        while (hexString.length() < 2) {
            hexString = "0" + hexString;
        }
        return hexString;
    }

    /**
     * 十六进制转byte
     */
    public byte[] hexStringToByteArray(String s) {
        int len = s.length();
        // 如果长度为奇数，则补一位'0'
        if (len % 2 != 0) {
            s = "0" + s;
            len = len + 1;
        }
        byte[] data = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            // 将十六进制的两个字符转换为一个字节
            data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
                    + Character.digit(s.charAt(i + 1), 16));
        }
        return data;
    }


    public static byte[] hexStringToByte(String hexString) {
        if (hexString == null || hexString.equals("")) {
            return null;
        }
        hexString = hexString.toLowerCase();
        final byte[] byteArray = new byte[hexString.length() >> 1];
        int index = 0;
        for (int i = 0; i < hexString.length(); i++) {
            if (index > hexString.length() - 1) {
                return byteArray;
            }
            byte highDit = (byte) (Character.digit(hexString.charAt(index), 16) & 0xFF);
            byte lowDit = (byte) (Character.digit(hexString.charAt(index + 1), 16) & 0xFF);
            byteArray[i] = (byte) (highDit << 4 | lowDit);
            index += 2;
        }
        return byteArray;
    }
}